/**
 * 页面导航工具模块
 * 提供增强的页面导航功能，支持事件通信和数据传递
 */

/**
 * 导航选项接口
 */
interface NavigateOptions {
  url: string // 目标页面路径
  params?: Record<string, unknown> // 查询参数
  events?: NavigateEvents // 自定义事件处理器
}

/**
 * 定义事件回调函数类型
 */
type EventCallback<T = unknown> = (data?: T) => void
type EventChannelCallback = (eventChannel: UniApp.EventChannel) => void

/**
 * 导航事件处理器
 */
interface NavigateEvents {
  [key: string]: EventCallback | EventChannelCallback | undefined
  init?: EventChannelCallback
  success?: EventCallback
}

/**
 * 带有事件通信的页面导航工具
 * 封装了 uni.navigateTo 和 eventChannel，支持页面间数据传递和回调处理
 *
 * @param options - 配置项
 * @returns 返回目标页面通过 eventChannel 传递的数据
 * @throws 当导航失败或发生其他错误时抛出异常
 *
 * @example
 * // 基础用法
 * const result = await navigateWithChannel({
 *   url: '/pages/detail',
 *   params: { id: 1 }
 * })
 *
 * // 使用 init 事件配置页面
 * const result = await navigateWithChannel({
 *   url: '/pages/selector',
 *   events: {
 *     init: (eventChannel) => {
 *       // 通过 eventChannel 发送初始化配置
 *       eventChannel.emit('initConfig', { multiple: true, preselected: ['1', '2'] })
 *     }
 *   }
 * })
 *
 * // 自定义事件处理
 * const result = await navigateWithChannel({
 *   url: '/pages/form',
 *   events: {
 *     submit: (data) => console.log(data),
 *   }
 * })
 */
export const navigateWithChannel = <T = unknown>({
  url,
  params = {},
  events = {},
}: NavigateOptions): Promise<T> => {
  return new Promise<T>((resolve, reject) => {
    // 构建带参数的URL
    const queryString = Object.entries(params)
      .map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`)
      .join('&')

    const fullUrl = queryString ? `${url}?${queryString}` : url

    // 创建自定义事件处理器（需要排除 init 事件，因为 init 事件需要特殊处理）
    const navEvents = {
      success: (data: T) => resolve(data),
    } as Record<string, EventCallback<T>>

    // 合并自定义事件处理器（除了 init）
    Object.entries(events).forEach(([key, handler]) => {
      key !== 'init' &&
        typeof handler === 'function' &&
        (navEvents[key] = handler as EventCallback<T>)
    })

    try {
      // 打开页面
      uni.navigateTo({
        url: fullUrl,
        events: navEvents,
        success: res => {
          // uni-app 规范：获取 eventChannel
          const eventChannel = res.eventChannel

          // 如果有 init 事件处理器，调用它并传入 eventChannel，因为它是从源页面向目标页面传递数据，所以需要先调用
          eventChannel && events?.init?.(eventChannel)
        },
        fail: err => reject(new Error(err.errMsg)),
      })
    } catch (error) {
      reject(new Error('页面导航失败: ' + (error as Error).message))
    }
  })
}

/**
 * 在目标页面中获取并使用 eventChannel
 *
 * @example
 * // 在目标页面的onLoad或setup中使用
 * const eventChannel = getEventChannel()
 *
 * // 监听初始化配置
 * eventChannel?.on('initConfig', (config) => {
 *   // 处理配置
 *   console.log('收到配置:', config)
 * })
 *
 * // 向来源页面发送数据
 * eventChannel?.emit('success', { result: 'done' })
 *
 * @returns 返回事件通道对象，如果无法获取则返回null
 */
export const getEventChannel = (): UniApp.EventChannel | null => {
  try {
    // @ts-expect-error - getOpenerEventChannel 在类型定义中不存在但运行时可用
    const channel = getCurrentPages()?.at(-1)?.getOpenerEventChannel?.()

    if (!channel) console.warn('获取eventChannel失败！')

    return channel || null
  } catch (error) {
    console.error('获取eventChannel失败:', error)
    return null
  }
}
